package crp.core.resource.domain.repositories;

import com.qwlabs.lang.C2;
import com.qwlabs.lang.S2;
import com.qwlabs.panache.Where;
import com.qwlabs.panache.query.PanacheQueries;
import crp.core.resource.domain.models.CourseResourceCount;
import crp.core.resource.domain.models.CourseResourceEntity;
import crp.core.shared.PublicStatus;
import crp.core.shared.PublishStatus;
import io.quarkus.hibernate.orm.panache.PanacheQuery;
import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase;
import io.quarkus.panache.common.Parameters;
import io.quarkus.panache.common.Sort;

import javax.enterprise.context.ApplicationScoped;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Stream;

@ApplicationScoped
public class CourseResourceRepository implements PanacheRepositoryBase<CourseResourceEntity, String> {
    public long deleteByResourceId(String resourceId) {
        return delete("resource.id = :resourceId",
                Parameters.with("resourceId", resourceId));
    }

    public PanacheQuery<CourseResourceEntity> findByCourseId(String courseId) {
        if (S2.isEmpty(courseId)) {
            return PanacheQueries.empty();
        }
        return find("course.id = :courseId",
                Parameters.with("courseId", courseId));
    }

    public Stream<CourseResourceEntity> findByResourceIds(Collection<String> resourceIds) {
        if (C2.isEmpty(resourceIds)) {
            return Stream.empty();
        }
        return find("resource.id in (:resourceIds)",
                Parameters.with("resourceIds", resourceIds)).stream();
    }

    public Stream<CourseResourceEntity> findByCourseIdsAndResourceIds(Set<String> courseIds, Collection<String> resourceIds) {
        if (C2.isEmpty(courseIds) || C2.isEmpty(resourceIds)) {
            return Stream.empty();
        }
        Where where = Where.create()
                .and("course.id in :courseIds", "courseIds", courseIds)
                .and("resource.id in :resourceIds", "resourceIds", resourceIds);
        return find(where.get(), Sort.by("updatedAt", Sort.Direction.Descending), where.getParameters()).stream();
    }

    public Stream<CourseResourceCount> countByCourseIds(Set<String> courseIds, PublicStatus publicStatus) {
        if (C2.isEmpty(courseIds)) {
            return Stream.empty();
        }
        return getEntityManager().createQuery("select new crp.core.resource.domain.models.CourseResourceCount(cr.course.id, count(cr.resource.id))" +
                " from CourseResourceEntity cr" +
                " where cr.course.id in (:courseIds) " +
                " and cr.resource.publicStatus=:publicStatus" +
                " group by cr.course")
                .setParameter("courseIds", courseIds)
                .setParameter("publicStatus", publicStatus)
                .getResultStream();
    }

    public Stream<CourseResourceCount> countByCourseIds(Set<String> courseIds, PublishStatus publishStatus) {
        if (C2.isEmpty(courseIds)) {
            return Stream.empty();
        }
        return getEntityManager().createQuery("select new crp.core.resource.domain.models.CourseResourceCount(cr.course.id, count(cr.resource.id))" +
                " from CourseResourceEntity cr" +
                " where cr.course.id in (:courseIds) " +
                " and cr.resource.publishStatus=:publishStatus" +
                " group by cr.course")
                .setParameter("courseIds", courseIds)
                .setParameter("publishStatus", publishStatus)
                .getResultStream();
    }

    public Stream<CourseResourceCount> countByCourseIds(Set<String> courseIds) {
        if (C2.isEmpty(courseIds)) {
            return Stream.empty();
        }
        return getEntityManager().createQuery("select new crp.core.resource.domain.models.CourseResourceCount(cr.course.id, count(cr.resource.id))" +
                " from CourseResourceEntity cr" +
                " where cr.course.id in (:courseIds) " +
                " group by cr.course")
                .setParameter("courseIds", courseIds)
                .getResultStream();
    }
}
